package com.robertlundberg.chess;

import java.util.ArrayList;
import java.util.List;
/**
 * class MoveGenerator
 * 
 * Manage the generation of legal moves on a chess board.
 * 
 * @author Robert Lundberg
 */
public class MoveGenerator {
	
	private Board chessboard;	
	
	public MoveGenerator(Board b)
	{
		this.chessboard = b;	
	}
	private List<Integer> GenerateWhiteMoves()
	{
		List<Integer> WhiteMoves = new ArrayList<Integer>();
		
		for(int pieceIndex = 0;pieceIndex < chessboard.WhitePieces.length;pieceIndex++)
		{			
			
			switch (chessboard.WhitePieces[pieceIndex]._type)
			{
				case WhiteKnight:
				{					
					for(int di = 0;di < chessboard.WhitePieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.WhitePieces[pieceIndex]._pieceDelta[di] + chessboard.WhitePieces[pieceIndex]._position;
						if((destination & 0x88) == 0) 
						{
							if(!chessboard.SquareHasWhitePiece(destination))
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex));
						}						
					}										
					break;
				}
				case WhiteBishop:
				{
					for(int di = 0;di < chessboard.WhitePieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.WhitePieces[pieceIndex]._pieceDelta[di] + chessboard.WhitePieces[pieceIndex]._position;
						
						while((destination & 0x88) == 0 && !chessboard.SquareHasWhitePiece(destination)) 
						{													
							if(chessboard.SquareIsEmpty(destination))
							{
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex));
							}
							else
							{
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex)); //Attacking move
								break;
							}
							
							destination += chessboard.WhitePieces[pieceIndex]._pieceDelta[di]; 
						}						
					}										
					break;
				}
				case WhiteRook:
				{										
					for(int di = 0;di < chessboard.WhitePieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.WhitePieces[pieceIndex]._pieceDelta[di] + chessboard.WhitePieces[pieceIndex]._position;
						
						while((destination & 0x88) == 0 && !chessboard.SquareHasWhitePiece(destination)) 
						{													
							if(chessboard.SquareIsEmpty(destination))
							{
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex));
							}
							else
							{
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex)); //Attacking move
								break;
							}
							
							destination += chessboard.WhitePieces[pieceIndex]._pieceDelta[di]; 
						}						
					}
					break;
				}
				case WhiteKing:
				{										
					for(int di = 0;di < chessboard.WhitePieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.WhitePieces[pieceIndex]._pieceDelta[di] + chessboard.WhitePieces[pieceIndex]._position;
						if((destination & 0x88) == 0) 
						{
							if(!chessboard.SquareHasWhitePiece(destination))
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex));
						}						
					}										
					break;
				}
				case WhiteQueen:
				{										
					for(int di = 0;di < chessboard.WhitePieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.WhitePieces[pieceIndex]._pieceDelta[di] + chessboard.WhitePieces[pieceIndex]._position;
						
						while((destination & 0x88) == 0 && !chessboard.SquareHasWhitePiece(destination)) 
						{													
							if(chessboard.SquareIsEmpty(destination))
							{
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex));
							}
							else
							{
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex)); //Attacking move
								break;
							}
							
							destination += chessboard.WhitePieces[pieceIndex]._pieceDelta[di]; 
						}						
					}
					break;
				}		
				case WhitePawn:
				{	
					
					for(int di = 0;di < chessboard.WhitePieces[pieceIndex]._pieceDelta.length;di++)					
					{							
						int destination = chessboard.WhitePieces[pieceIndex]._pieceDelta[di] + chessboard.WhitePieces[pieceIndex]._position;
						if((destination & 0x88) == 0) 
						{
							if(!chessboard.SquareHasWhitePiece(destination) && !chessboard.SquareHasBlackPiece(destination))
								WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex));
							else
								break;
						}	
						if(chessboard.WhitePieces[pieceIndex]._position > 23)//Is the pawn at its starting position?
							break;//Breaking out of the _pieceDelta for-loop e.g only one square advance is allowed.
					}	
					//Attacking moves
					for(int di = 0;di < chessboard.WhitePieces[pieceIndex]._attackDelta.length;di++)					
					{			
						int destination = chessboard.WhitePieces[pieceIndex]._attackDelta[di] + chessboard.WhitePieces[pieceIndex]._position;
						if((destination & 0x88) == 0 && chessboard.SquareHasBlackPiece(destination)) 
						{							
							WhiteMoves.add(Move.EncodeMove(chessboard.WhitePieces[pieceIndex]._position, destination, pieceIndex));
						}						
					}	
					break;
				}			
			}
			
		}
		return WhiteMoves;
	}
	///////////////////////
	private List<Integer> GenerateBlackMoves()
	{
		List<Integer> BlackMoves = new ArrayList<Integer>();
		for(int pieceIndex = 0;pieceIndex < chessboard.BlackPieces.length;pieceIndex++)
		{			
			
			switch (chessboard.BlackPieces[pieceIndex]._type)
			{
				case BlackKnight:
				{					
					for(int di = 0;di < chessboard.BlackPieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.BlackPieces[pieceIndex]._pieceDelta[di] + chessboard.BlackPieces[pieceIndex]._position;
						if((destination & 0x88) == 0) 
						{
							if(!chessboard.SquareHasBlackPiece(destination))
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex));
						}						
					}										
					break;
				}
				case BlackBishop:
				{
					for(int di = 0;di < chessboard.BlackPieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.BlackPieces[pieceIndex]._pieceDelta[di] + chessboard.BlackPieces[pieceIndex]._position;
						
						while((destination & 0x88) == 0 && !chessboard.SquareHasBlackPiece(destination)) 
						{													
							if(chessboard.SquareIsEmpty(destination))
							{
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex));
							}
							else
							{
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex)); //Attacking move
								break;
							}
							
							destination += chessboard.BlackPieces[pieceIndex]._pieceDelta[di]; 
						}						
					}										
					break;
				}
				case BlackRook:
				{										
					for(int di = 0;di < chessboard.BlackPieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.BlackPieces[pieceIndex]._pieceDelta[di] + chessboard.BlackPieces[pieceIndex]._position;
						
						while((destination & 0x88) == 0 && !chessboard.SquareHasBlackPiece(destination)) 
						{													
							if(chessboard.SquareIsEmpty(destination))
							{
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex));
							}
							else
							{
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex)); //Attacking move
								break;
							}
							
							destination += chessboard.BlackPieces[pieceIndex]._pieceDelta[di]; 
						}						
					}
					break;
				}
				case BlackKing:
				{										
					for(int di = 0;di < chessboard.BlackPieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.BlackPieces[pieceIndex]._pieceDelta[di] + chessboard.BlackPieces[pieceIndex]._position;
						if((destination & 0x88) == 0) 
						{
							if(!chessboard.SquareHasBlackPiece(destination))
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex));
						}						
					}										
					break;
				}
				case BlackQueen:
				{										
					for(int di = 0;di < chessboard.BlackPieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.BlackPieces[pieceIndex]._pieceDelta[di] + chessboard.BlackPieces[pieceIndex]._position;
						
						while((destination & 0x88) == 0 && !chessboard.SquareHasBlackPiece(destination)) 
						{													
							if(chessboard.SquareIsEmpty(destination))
							{
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex));
							}
							else
							{
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex)); //Attacking move
								break;
							}
							
							destination += chessboard.BlackPieces[pieceIndex]._pieceDelta[di]; 
						}						
					}
					break;
				}		
				case BlackPawn:
				{					
					for(int di = 0;di < chessboard.BlackPieces[pieceIndex]._pieceDelta.length;di++)					
					{			
						int destination = chessboard.BlackPieces[pieceIndex]._pieceDelta[di] + chessboard.BlackPieces[pieceIndex]._position;
						if((destination & 0x88) == 0) 
						{
							if(!chessboard.SquareHasBlackPiece(destination) && !chessboard.SquareHasWhitePiece(destination))
								BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex));
							else
								break;
						}
						if(chessboard.BlackPieces[pieceIndex]._position < 96)//Is the pawn at its starting position?
							break;//Breaking out of the _pieceDelta for-loop e.g only one square advance is allowed.
					}	
					//Attacking moves
					for(int di = 0;di < chessboard.BlackPieces[pieceIndex]._attackDelta.length;di++)					
					{			
						int destination = chessboard.BlackPieces[pieceIndex]._attackDelta[di] + chessboard.BlackPieces[pieceIndex]._position;
						if((destination & 0x88) == 0 && chessboard.SquareHasWhitePiece(destination)) 
						{							
							BlackMoves.add(Move.EncodeMove(chessboard.BlackPieces[pieceIndex]._position, destination, pieceIndex));
						}						
					}	
					break;
				}			
			}
			
		}
		return BlackMoves;
	}
	///////////////
		
	public List<Integer> GenerateMoves()
	{
		if(chessboard.SideToMove == Board.Color.White)
			return GenerateWhiteMoves();
		else
			return GenerateBlackMoves();	
	}
	

}